package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.constants.AilyvnConstant;
import com.heima.common.constants.Constant;
import com.heima.common.constants.NewsConstant;
import com.heima.common.exception.CustomException;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.feign.client.ApArticleClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.acticle.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.common.enums.NewsStatusEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.ITextAndImageService;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.TesseractException;
import org.apache.commons.lang.text.StrBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class TextAndImageServiceImpl extends ServiceImpl<WmNewsMapper,WmNews> implements ITextAndImageService {

    @Resource
    private GreenTextScan greenTextScan;

    @Resource
    private GreenImageScan greenImageScan;

    @Resource
    private FileStorageService fileStorageService;

    @Resource
    private WmNewsMapper wmNewsMapper;

    @Resource
    private ApArticleClient apArticleApi;

    @Resource
    private WmUserMapper wmUserMapper;

    @Resource
    private WmChannelMapper wmChannelMapper;

    @Resource
    private WmSensitiveMapper wmSensitiveMapper;

    @Resource
    private Tess4jClient tess4jClient;

    /**
     * 文章审核
     * @param wmNews
     */
    @Override
    @Async
    public void articeleModeration(WmNews wmNews){
        //1.获取文章与图片
        Map<String, Object> textAndImage = getTextAndImage(wmNews);
        try {
            List<String> imagesUrl = (List<String>) textAndImage.get(NewsConstant.MAP_KEY_ONE);
            //7.图片中的文字获取
            String imageInText = imageInText(imagesUrl);
            //6.自定义文章审核（公司内部）
            sensitivScan(textAndImage.get(NewsConstant.MAP_KEY_TWO) + imageInText,wmNews);
            //2.文章文本审核
            if (!(wmNews.getStatus() == NewsStatusEnum.STATUS_NEWS_TWO)){
                textSan(textAndImage.get(NewsConstant.MAP_KEY_TWO) + imageInText,wmNews);
            }
            //3.文章图片审核
            if (wmNews.getStatus() == NewsStatusEnum.STATUS_NEWS_EIGHT){
                imageScan(imagesUrl,wmNews);
            }
            //5.调用app端接口 方法为异步，不能在外面执行
            if (wmNews.getStatus() == NewsStatusEnum.STATUS_NEWS_EIGHT){
                getArticleIdBySave(wmNews);
            }
        } catch (Exception e) {
            //走人工
            log.error("程序繁忙中,由人工处理,{}",e.getMessage());
            extracted(wmNews,NewsStatusEnum.STATUS_NEWS_THREE,e.getMessage());
        }
    }

    private String imageInText(List<String> imagesUrl) throws IOException, TesseractException {
        //
        StringBuilder imageText = new StringBuilder();
        if (imagesUrl.isEmpty()){
            return imageText.toString();
        }
        //
        for (String image : imagesUrl) {
            byte[] bytes = fileStorageService.downLoadFile(image);
            String doOCR = tess4jClient.doOCR(ImageIO.read(new ByteArrayInputStream(bytes)));
            imageText.append(",").append(doOCR);
        }
        return imageText.toString();
    }

    /**
     * 自定义文章审核（公司内部）
     * @param text
     * @param wmNews
     */
    //TODO 可在最开始初始化1和2，来优化代码
    private void sensitivScan(String text, WmNews wmNews) {
        //1.获取现有的敏感词
        List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(null);
        if (null == wmSensitives){
            log.info("敏感词字典为空");
            return;
        }
        //2.初始化
        SensitiveWordUtil
                .initMap(wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList()));
        //3.审核文本
        Map<String, Integer> map = SensitiveWordUtil.matchWords(text);
        log.info("文本中的敏感词，{}",map);
        if (!map.isEmpty()){
            extracted(wmNews,NewsStatusEnum.STATUS_NEWS_TWO, JSON.toJSONString(map));
        }
    }

    /**
     * 调用app端接口,获得app端文章id
     * @param wmNews
     * @return
     */
    private void getArticleIdBySave(WmNews wmNews) {
        ArticleDto dto = new ArticleDto();
        BeanUtils.copyProperties(wmNews,dto);
        //
        dto.setAuthorId(wmNews.getUserId());
        dto.setAuthorName(wmUserMapper.selectById(wmNews.getUserId()).getNickname());
        //
        dto.setLayout(wmNews.getType());
        dto.setChannelName(wmChannelMapper.selectById(wmNews.getChannelId()).getName());
        dto.setPublishTime(LocalDateTime.now());
        //
        ResponseResult result = apArticleApi.save(dto);
        log.info("app端返回的结果，{}", result.getData());

        if (result.getCode() == AppHttpCodeEnum.SUCCESS.getCode()){
            Long id = (Long)result.getData();
            wmNews.setArticleId(id);
            wmNews.setStatus(NewsStatusEnum.STATUS_NEWS_NINE);
            wmNewsMapper.updateById(wmNews);
        }

    }

    /**
     * 文章图片审核
     * @param images
     * @param wmNews
     * @throws Exception
     */
    private void imageScan(List<String> images,WmNews wmNews) throws Exception {
        //1.
        List<byte[]> collect = images.stream()
                .map(image -> fileStorageService.downLoadFile(image)).collect(Collectors.toList());
        //2.
        Map map = greenImageScan.imageScan(collect);
        log.info("图片审核结果，{}",map);
        //3.
        scanAbled(map,wmNews);
    }
    /**
     * 审核文章内容
     * @param text
     */
    private void textSan(String text,WmNews wmNews) throws Exception {
        //1.
        Map map = greenTextScan.greeTextScan(text);
        log.info("文章审核结果,{}",map);
        //2.审核结果可能性
        scanAbled(map,wmNews);
    }

    /**
     * 审核结果可能性
     * @param map
     */
    private void scanAbled(Map map,WmNews wmNews) {
        if (null == map){
            log.info("自动审核异常，需走人工");
            extracted(wmNews,NewsStatusEnum.STATUS_NEWS_THREE,AppHttpCodeEnum.ALIYVN_LINK_DEFEAT.getErrorMessage());
            return;
        }
        if (AilyvnConstant.SAFE_TYPE_TWO.equals((String) map.get(AilyvnConstant.SAFE_KEY_ONE))){
            log.info("结果违规，建议直接删除或者限制公开");
            extracted(wmNews,NewsStatusEnum.STATUS_NEWS_TWO,(String) map.get(AilyvnConstant.SAFE_ERROR_MSG_KEY));
        }else if (AilyvnConstant.SAFE_TYPE_THREE.equals((String) map.get(AilyvnConstant.SAFE_KEY_ONE))){
            log.info("结果不确定，需要进行人工审核");
            extracted(wmNews,NewsStatusEnum.STATUS_NEWS_THREE,(String) map.get(AilyvnConstant.SAFE_ERROR_MSG_KEY));
        }else {
            log.info("审核通过");
            extracted(wmNews,NewsStatusEnum.STATUS_NEWS_EIGHT,null);
        }
    }

    /**
     * 审核结果设置
     * @param wmNews
     * @param msg
     */
    private void extracted(WmNews wmNews,NewsStatusEnum newsStatusEnum,String msg) {
        wmNews.setStatus(newsStatusEnum);
        wmNews.setReason(msg);
        wmNewsMapper.updateById(wmNews);
    }

    /**
     * 获取文章与图片
     * @param wmNews
     */
    private Map<String,Object> getTextAndImage(WmNews wmNews) {
        //1.
        List<Map> mapList = JSONArray.parseArray(wmNews.getContent(), Map.class);
        //2.
        List<String> images = new ArrayList<>();
        StrBuilder text = new StrBuilder();
        mapList.stream().map(map -> {
            String type = map.get(NewsConstant.JSON_TYPE_ONE)+Constant.NULL;
            String value = map.get(NewsConstant.JSON_TYPE_TWO)+Constant.NULL;

            if (type.equals(NewsConstant.JSON_VALUE_ONE)){
                //图片
                images.add(value);
            }else {
                //内容
                text.append(value);
            }
            return map;
        }).collect(Collectors.toList());

        //标题和图片
        text.append(Constant.BOOK_TITEL_LEFT+wmNews.getTitle()+Constant.BOOK_TITEL_REGHT);
        if (!StringUtils.isEmpty(wmNews.getImages())){
            images.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(wmNews.getImages())));
            //去重
            images.stream().distinct().collect(Collectors.toList());
        }
        //3.
        Map<String,Object> map = new HashMap<>();
        map.put(NewsConstant.MAP_KEY_ONE,images);
        map.put(NewsConstant.MAP_KEY_TWO,text);

        return map;
    }
}
